package priv.pfz.raft.peer.model;

import com.google.common.collect.Maps;
import lombok.Getter;
import lombok.Setter;
import priv.pfz.raft.common.ToString;
import priv.pfz.raft.peer.RaftEventQueue;
import priv.pfz.raft.peer.enums.PeerState;

import java.util.Map;

/**
 * @author pengfangzhou
 * @date 2022/2/3 18:17
 */
@Getter
@Setter
public class PeerData extends ToString {
    /** 当前状态 */
    private PeerState state;

    /** 任期属性 */
    //当前任期
    private int currentTerm = -1;
    //当前任期的领导
    private String currentLeader;
    //当前任期
    private String votedFor;
    private Integer currentIndex;
    private RaftEventQueue electionQueue;
    private Map<String, OtherPeerInfo> otherPeerInfoMap = Maps.newHashMap();
    private int grantedCount;
    private int deniedCount;

    /** 日志 */
    private Logs logs = new Logs();
    private Integer currentValue;

    public OtherPeerInfo getOtherPeerInfo(String peer) {
        return otherPeerInfoMap.get(peer);
    }

    public void incrCurrentIndex() {
        this.currentIndex++;
    }

    public void incrGrantedCount() {
        this.grantedCount++;
    }

    public void incrDeniedCount() {
        this.deniedCount++;
    }

    /**
     * 任期内更换状态时清理
     */
    public void clearForStateUpdate() {
        //关闭选举计时器
        electionQueue.clear();
        //关闭rpc计时器，停止发送拉票/心跳/日志复制请求
        for (OtherPeerInfo otherPeerInfo : otherPeerInfoMap.values()) {
            otherPeerInfo.getRpcQueue().clear();
            otherPeerInfo.setConnecting(false);
        }
    }

    /**
     * 更新任期时清理
     */
    public void clearForTermUpdate(int term) {
        currentTerm = term;
        currentLeader = null;
        votedFor = null;
        currentIndex = 0;
        for (OtherPeerInfo otherPeerInfo : otherPeerInfoMap.values()) {
            otherPeerInfo.setMaxLogKey(LogKey.DEFAULT);
            otherPeerInfo.setVoteGranted(null);
        }
        grantedCount = 0;
        deniedCount = 0;
        clearForStateUpdate();
    }

    /**
     * 本地日志比指定节点日志多
     * 1、本地无日志，一定返回false
     * 2、本地有日志，leader上任后从未拿到对方的日志进度信息，一定返回true
     * 3、本地有日志，已知otherPeer的日志进度，根据大小返回
     */
    public boolean hasDiffLog(String peerName) {
        LogKey localLog = logs.getLastLogKey();
        LogKey followerLog = otherPeerInfoMap.get(peerName).getMaxLogKey();
        return localLog.compareTo(followerLog) > 0;
    }
}
